﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Windows.Media.Imaging;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Media;
using Microsoft.Phone.Tasks;
using System.IO;

namespace NiklasKarl.WarpCam.Pages
{
    public partial class PreviewPage : PhoneApplicationPage
    {
        bool m_isTombstoned;

        bool m_isPinching;
        Point m_primaryContact;
        Point m_secondaryContact;
        Point m_center;

        Point m_translation;
        double m_scale;


        #region ImageUri

        public static readonly DependencyProperty ImageUriProperty = DependencyProperty.Register(
            "ImageUri", typeof(Uri), typeof(PreviewPage), new PropertyMetadata(null, OnImageUriPropertyChanged));

        public Uri ImageUri
        {
            get { return GetValue(ImageUriProperty) as Uri; }
            set { SetValue(ImageUriProperty, value); }
        }

        private static void OnImageUriPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            (o as PreviewPage).OnImageUriChanged();
        }

        private void OnImageUriChanged()
        {
            if (PreviewImage != null)
            {
                BitmapImage source = null;

                if (ImageUri != null)
                {
                    source = new BitmapImage(ImageUri);
                }

                PreviewImage.Source = source;

                m_translation = new Point();
                m_scale = 1.0;

                AbortStoryboard();
            }
        }

        #endregion

        #region SharePath

        public static readonly DependencyProperty SharePathProperty = DependencyProperty.Register(
            "SharePath", typeof(string), typeof(PreviewPage), new PropertyMetadata(null, OnSharePathPropertyChanged));

        public string SharePath
        {
            get { return GetValue(SharePathProperty) as string; }
            set { SetValue(SharePathProperty, value); }
        }

        private static void OnSharePathPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            (o as PreviewPage).OnSharePathChanged();
        }

        private void OnSharePathChanged()
        {

        }

        #endregion

        public PreviewPage()
        {
            InitializeComponent();

            m_isTombstoned = true;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (e.NavigationMode == NavigationMode.New)
            {
                OnImageUriChanged();
            }
            else if (m_isTombstoned)
            {
                if (State.ContainsKey("ImageUri"))
                {
                    ImageUri = State["ImageUri"] as Uri;
                }

                if (State.ContainsKey("SharePath"))
                {
                    SharePath = State["SharePath"] as string;
                }
                
                m_isTombstoned = false;
            }

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            if (e.NavigationMode != NavigationMode.Back)
            {
                State["ImageUri"] = ImageUri;
                State["SharePath"] = SharePath;
            }

            base.OnNavigatedFrom(e);
        }

        private void PreviewImageContainer_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            GeneralTransform transform = e.ManipulationContainer.TransformToVisual(PreviewImageContainer);

            m_center = transform.Transform(e.ManipulationOrigin);

            AbortStoryboard();
        }

        private void PreviewImageContainer_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            GeneralTransform transform = e.ManipulationContainer.TransformToVisual(PreviewImageContainer);

            if (e.PinchManipulation != null)
            {
                if (m_isPinching)
                {
                    PinchContactPoints current = e.PinchManipulation.Current;
                    Point primaryContact = transform.Transform(current.PrimaryContact);
                    Point secondaryContact = transform.Transform(current.SecondaryContact);
                    Point center = transform.Transform(current.Center);

                    Point scaleCenter = new Point(
                        m_translation.X + PreviewImageContainer.ActualWidth / 2.0,
                        m_translation.Y + PreviewImageContainer.ActualHeight / 2.0
                        );

                    double scale = GetDistance(primaryContact, secondaryContact) / GetDistance(m_primaryContact, m_secondaryContact);
                    scale = Clamp(scale, 0.8 / m_scale, 3.2 / m_scale);

                    Point translation = new Point(
                        (scaleCenter.X - m_center.X) * (scale - 1.0),
                        (scaleCenter.Y - m_center.Y) * (scale - 1.0)
                        );

                    PreviewImageTransform.ScaleX = m_scale * scale;
                    PreviewImageTransform.ScaleY = m_scale * scale;
                    PreviewImageTransform.TranslateX = m_translation.X + translation.X;
                    PreviewImageTransform.TranslateY = m_translation.Y + translation.Y;
                }
                else
                {
                    PinchContactPoints current = e.PinchManipulation.Current;

                    m_primaryContact = transform.Transform(current.PrimaryContact);
                    m_secondaryContact = transform.Transform(current.SecondaryContact);
                    m_center = transform.Transform(current.Center);

                    m_scale = (PreviewImageTransform.ScaleX + PreviewImageTransform.ScaleY) / 2.0;
                    m_translation = new Point(PreviewImageTransform.TranslateX, PreviewImageTransform.TranslateY);

                    m_isPinching = true;
                }
            }
            else
            {
                if (m_isPinching)
                {
                    m_center = transform.Transform(e.ManipulationOrigin);

                    m_scale = (PreviewImageTransform.ScaleX + PreviewImageTransform.ScaleY) / 2.0;
                    m_translation = new Point(PreviewImageTransform.TranslateX, PreviewImageTransform.TranslateY);

                    m_isPinching = false;
                }
                else
                {
                    Point center = transform.Transform(e.ManipulationOrigin);

                    PreviewImageTransform.TranslateX = m_translation.X + center.X - m_center.X;
                    PreviewImageTransform.TranslateY = m_translation.Y + center.Y - m_center.Y;
                }
            }
        }

        private void PreviewImageContainer_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            GeneralTransform transform = e.ManipulationContainer.TransformToVisual(PreviewImageContainer);

            m_scale = (PreviewImageTransform.ScaleX + PreviewImageTransform.ScaleY) / 2.0;
            m_scale = Clamp(m_scale, 1.0, 3.0);

            m_translation = new Point(PreviewImageTransform.TranslateX, PreviewImageTransform.TranslateY);

            double x = Math.Max(0.0, (PreviewImage.ActualWidth * m_scale - PreviewImageContainer.ActualWidth) / 2.0);
            double y = Math.Max(0.0, (PreviewImage.ActualHeight * m_scale - PreviewImageContainer.ActualHeight) / 2.0);

            m_translation = new Point(
                Clamp(m_translation.X, -x, x),
                Clamp(m_translation.Y, -y, y)
                );

            m_isPinching = false;

            StartStoryboard();
        }

        private void StartStoryboard()
        {
            ResetScaleXAnimation.To = m_scale;
            ResetScaleYAnimation.To = m_scale;

            ResetTranslateXAnimation.To = m_translation.X;
            ResetTranslateYAnimation.To = m_translation.Y;

            ResetStoryboard.Begin();
        }

        private void AbortStoryboard()
        {
            ResetStoryboard.Stop();

            PreviewImageTransform.ScaleX = m_scale;
            PreviewImageTransform.ScaleY = m_scale;

            PreviewImageTransform.TranslateX = m_translation.X;
            PreviewImageTransform.TranslateY = m_translation.Y;
        }

        private double Clamp(double value, double low, double high)
        {
            return Math.Min(high, Math.Max(low, value));
        }

        private double GetDistance(Point p1, Point p2)
        {
            double dX = p2.X - p1.X;
            double dY = p2.Y - p1.Y;

            return Math.Sqrt(dX * dX + dY * dY);
        }

        private void ShareButton_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(SharePath))
            {
                ShareMediaTask task = new ShareMediaTask();
                task.FilePath = SharePath;
                task.Show();
            }
        }
    }
}